using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Microsoft.BizTalk.ExplorerOM;
using Microsoft.BizTalk.ApplicationDeployment;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading;
using System.Configuration;
using System.Xml.Serialization;
using System.Xml;
using Microsoft.Win32;
using System.Data.SqlClient;

namespace Blogical.Tools.BizTalkUndeployHelper
{
    public partial class Main : Form
    {
        #region SQL Query
        string getUnusedAssembliesQuery = @"select nvcFullName 
from bts_assembly
where nSystemAssembly = 0
and nId not in
(Select  map.assemblyid
from    bts_receiveport_transform tr
join    bt_MapSpec map on tr.uidTransformGUID = map.id
join    bts_item itm on map.itemid = itm.id
join    bts_receiveport rcv on rcv.nID = tr.nReceivePortID
union
Select  map.assemblyid
from    bts_sendport_transform tr
join    bt_MapSpec map on tr.uidTransformGUID = map.id
join    bts_item itm on map.itemid = itm.id
join    bts_sendport snd on snd.nID = tr.nSendPortID
union
select  nAssemblyID
from    adm_receiveLocation loc
join    bts_pipeline pipe on pipe.ID = loc.ReceivePipelineId
union
select  nAssemblyID
from    bts_sendport snd
join    bts_pipeline pipe on pipe.ID = snd.nSendPipelineId
union
Select  distinct o.nAssemblyID
from	bts_orchestration o
join	bts_orchestration_port op on op.nOrchestrationID = o.nid
join	bts_orchestration_port_binding b on b.nID = op.nID
where coalesce(b.nreceiveportid, b.nsendportid) is not null)";
        #endregion

        #region Private Members
        List<AssemblyResource> _assemblyResources = new List<AssemblyResource>();
        List<AssemblyResource> _undeploySequense = new List<AssemblyResource>();
        List<ListViewItem> _assemblylist = new List<ListViewItem>();
        BtsCatalogExplorer _explorer = null;
        string _scriptFilename;
        #endregion
        
        #region Form Events
        public Main()
        {
            InitializeComponent();
        }
        private void Main_Load(object sender, EventArgs e)
        {
            this.Height = 500;
            // Set the defaults
            txtDatabase.Text = "BizTalkMgmtDb";
            txtServer.Text = Environment.MachineName;

            RegistryKey rk =Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\BizTalk Server\3.0\Administration");
            
            if (rk != null)
            {
                txtDatabase.Text = (string)rk.GetValue("MgmtDBName");
                txtServer.Text = (string)rk.GetValue("MgmtDBServer");
            }

        }
        private void btnNext_Click(object sender, EventArgs e)
        {
            if (((Button)sender).Text == "Undeploy")
            {
                if (MessageBox.Show("Are you sure you want to undeploy these assemblies and artifacts?", "Confirm undeploy", MessageBoxButtons.YesNo, MessageBoxIcon.Exclamation) == DialogResult.Yes)
                {
                    btnNext.Enabled = false;
                    tabControl1.SelectedIndex++;
                    Undeploy();

                    if (MessageBox.Show("Do you want to save these undeploy settings?", "Save undeploy settings", MessageBoxButtons.YesNo) == DialogResult.No)
                    {
                        File.Delete(_scriptFilename);
                    }
                    else
                    {
                        SaveFileDialog saveFileDialog1 = new SaveFileDialog();
                        saveFileDialog1.Filter = "xml files (*.xml)|*.xml";
                        saveFileDialog1.RestoreDirectory = true;
                        saveFileDialog1.AddExtension = true;


                        if (saveFileDialog1.ShowDialog() == DialogResult.OK)
                        {
                            File.Move(_scriptFilename, saveFileDialog1.FileName);
                        }
                    }
                    imgProgress.Visible = false;
                    btnNext.Enabled = true;
                }
            }
            else if (((Button)sender).Text == "Close")
                this.Close();
            else if (tabControl1.SelectedIndex == 0 &&
                txtServer.Text.ToLower() != "localhost"
                && txtServer.Text.ToLower() != Environment.MachineName.ToLower())
            {
                if (MessageBox.Show("Running the application against a remote server might not work, since all assemblies need to be installed on this mashine (" + Environment.MachineName + ").",
                        this.Text, MessageBoxButtons.OKCancel) == DialogResult.OK)
                    tabControl1.SelectedIndex++;
            }
            else if (tabControl1.SelectedIndex == 1)
            {
                _scriptFilename = "AssemblyResources_"+DateTime.Now.ToString().Replace(":","") +".xml";
                _scriptFilename = _scriptFilename.Replace("/", "-");
                if(File.Exists(_scriptFilename))
                    File.Delete(_scriptFilename);

                XmlSerializer ser = new XmlSerializer(typeof(List<AssemblyResource>));
                FileStream stream = File.Open(_scriptFilename,FileMode.CreateNew);
                ser.Serialize(stream, _undeploySequense);
                stream.Close();
                tabControl1.SelectedIndex++;
            }
            else
                tabControl1.SelectedIndex++;
            
        }
        private void btnBack_Click(object sender, EventArgs e)
        {
            tabControl1.SelectedIndex--;
        }
        private void btsClear_Click(object sender, EventArgs e)
        {
            _undeploySequense.Clear();

            foreach (ListViewItem lvi in lstAssemblies.Items)
            {
                lvi.Checked = false;
            }
        }
        private void btsRefresh_Click(object sender, EventArgs e)
        {
            lstAssemblies.Items.Clear();
            GetAssemblies();
        }
        private void btnLoad_Click(object sender, EventArgs e)
        {
            OpenFileDialog fd = new OpenFileDialog();
            if (fd.ShowDialog() == DialogResult.OK)
            {
                FileStream stream = File.Open(fd.FileName, FileMode.Open);

                XmlSerializer ser = new XmlSerializer(typeof(List<AssemblyResource>));
                _undeploySequense = (List<AssemblyResource>)ser.Deserialize(stream);
                stream.Close();
                List<string> luids = new List<string>();

                foreach (AssemblyResource ar in _undeploySequense)
                    if (ar.Selected)
                        luids.Add(ar.Luid);

                btsClear_Click(null, null);

                foreach (string luid in luids)
                    foreach (ListViewItem lvi in lstAssemblies.Items)
                        if (lvi.Text == luid)
                            lvi.Checked = true;

            }
        }
        private void btnMarkUnused_Click(object sender, EventArgs e)
        {
            string connectionString = string.Format("server={0};database={1};integrated security=true", txtServer.Text, txtDatabase.Text);

            List<ListViewItem> listViewItems = new List<ListViewItem>();
            List<AssemblyResource> unUsedAssemblies = new List<AssemblyResource>();
            foreach (ListViewItem lvi in lstAssemblies.Items)
                listViewItems.Add(lvi);

            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();

                SqlCommand command = new SqlCommand(getUnusedAssembliesQuery, connection);
                SqlDataReader reader = command.ExecuteReader();
                while (reader.Read())
                    unUsedAssemblies.Add(_assemblyResources.First(a => a.Luid == reader["nvcFullName"].ToString()));
            }

            foreach (AssemblyResource assemblyResource in unUsedAssemblies)
            {
                if (IsUsedInOrchestrations(assemblyResource.Luid))
                    continue;
                bool add = true;
                //
                foreach (AssemblyResource refAss in GetAllReferencingAssemblies(assemblyResource))
                {
                    int refCount = unUsedAssemblies.Where(a => a.Luid == refAss.Luid).Count();
                    if (refCount == 0 || IsUsedInOrchestrations(refAss.Luid))
                    {
                        add = false;
                        break;
                    }
                }
                if (add)
                {
                    try
                    {
                        listViewItems.First(l => l.Text == assemblyResource.Luid).Checked = true;
                    }
                    catch { }
                }
            }
        }
        private void lstAssemblies_SelectedIndexChanged(object sender, EventArgs e)
        {

        }
        private void tabControl1_SelectedIndexChanged(object sender, EventArgs e)
        {
            btnBack.Enabled = tabControl1.SelectedIndex != 0;

            switch (tabControl1.SelectedIndex)
            {
                case 0:
                    btnBack.Visible = false;
                    break;
                case 1:
                    if (lstAssemblies.Items.Count == 0)
                        GetAssemblies();
                    btnNext.Text = "Next";
                    btnNext.Enabled = false;
                    btnBack.Visible = true;
                    break;
                case 2:
                    btnNext.Text = "Undeploy";
                    lvUndeploy.Items.Clear();
                    lvBizTalkArtefacts.Items.Clear();


                    GetAssemblyProcess waitDialog = new GetAssemblyProcess();
                    waitDialog.progressBar1.Maximum = _undeploySequense.Count() + 1;
                    waitDialog.Text = "Preparing undeploy";
                    waitDialog.SetLabel("Building dependancy order...");
                    waitDialog.Show(this);

                    AssemblyHelper helper = new AssemblyHelper();
                    foreach (AssemblyResource assemblyResource in _undeploySequense)
                        helper.Assemblies.Add(new BizTalkAssembly() { Application = assemblyResource.Application, Luid=assemblyResource.Luid});
                    
                        helper.SetReferences();

                    List<BizTalkAssembly> buildOrder = helper.GetBuildOrder();
                    int order = 1;

                    System.Windows.Forms.Application.DoEvents();

                    foreach (BizTalkAssembly assembly in buildOrder)
                    {
                        waitDialog.SetLabel("Getting related artefacts for " + assembly.Luid);
                        ListViewItem lvi = new ListViewItem(order.ToString());
                        lvi.Tag = assembly.Application;
                        lvi.SubItems.Add(assembly.Luid);
                        lvi.SubItems.Add(assembly.Application);
                        lvUndeploy.Items.Add(lvi);
                        order++;
                        GetBizTalkArtefactsToUndeploy(assembly);
                    }
                    waitDialog.Close();

                    break;
                case 3:
                    btnNext.Text = "Close";
                    btnBack.Visible = false;
                    break;
            }

        }
        private void lstBindingFiles_ItemChecked(object sender, ItemCheckedEventArgs e)
        {
            ListViewItem lvi = e.Item;

            if (lvi.Checked)
            {
                if (lvi.SubItems[1].Text == "")
                {
                    lvi.SubItems[1].Text = "Selected";
                    ((AssemblyResource)lvi.Tag).Selected = true;
                    System.Diagnostics.Trace.WriteLine(lvi.SubItems[0].Text + "\tselected");
                }
                _undeploySequense.Add((AssemblyResource)lvi.Tag);
                
                // Get All referencing assemblies
                foreach (AssemblyResource ar in GetAllReferencingAssemblies((AssemblyResource)lvi.Tag))
                {
                    foreach (ListViewItem li in lstAssemblies.Items)
                    {
                        if (((AssemblyResource)li.Tag).Luid == ar.Luid)
                        {
                            if (!li.Checked)
                            {
                                li.SubItems[1].Text = "Ref";
                                li.Checked = true;
                                System.Diagnostics.Trace.WriteLine(li.SubItems[0].Text + "\tadded byref");
                            }
                            else 
                            {
                                li.SubItems[1].Text = "Ref";
                                li.Font = new Font(li.Font, FontStyle.Regular);
                                ((AssemblyResource)li.Tag).Selected = false;
                                System.Diagnostics.Trace.WriteLine(li.SubItems[0].Text + "\tadded byref");
                            }
                        }
                    }
                }
                // Check for orchestrations
                CheckForOrchestrations(((AssemblyResource)lvi.Tag).Luid);
                if (lvi.SubItems[1].Text == "Selected")
                    lvi.Font = new Font(lvi.Font, FontStyle.Bold);
                else
                    lvi.Font = new Font(lvi.Font, FontStyle.Regular);
            }
            else
            {
                lvi.SubItems[1].Text = "";
                lvi.Font = new Font(lvi.Font, FontStyle.Regular);
                _undeploySequense.Remove((AssemblyResource)lvi.Tag);
            }
            btnNext.Enabled = lstAssemblies.CheckedItems.Count > 0;
        }
        #endregion

        #region Private Methods
        /// <summary>
        /// Establish the connection to BizTalk
        /// </summary>
        void InitCatalogExplorer()
        {
            if (_explorer == null)
            {
                if (String.IsNullOrEmpty(txtServer.Text))
                {
                    MessageBox.Show("Please select a server.");
                    return;
                }
                _explorer = new BtsCatalogExplorer();
                try
                {
                    _explorer.ConnectionString = string.Format("server={0};database={1};integrated security=true", txtServer.Text, txtDatabase.Text);
                }
                catch
                {
                    MessageBox.Show("Unable to connect to server.");
                    return;
                }
            }
            else
                _explorer.Refresh();
        }
        /// <summary>
        /// Populates lstAssemblies with all BizTalk assemblies 
        /// </summary>
        void GetAssemblies()
        {
            this.Cursor = Cursors.WaitCursor;

            GetAssemblyProcess waitDialog = new GetAssemblyProcess();
            waitDialog.Show(this);
            System.Windows.Forms.Application.DoEvents();

            InitCatalogExplorer();
            System.Windows.Forms.Application.DoEvents();

            List<BtsAssembly> assemblies = new List<BtsAssembly>();

            foreach (BtsAssembly ass in _explorer.Assemblies)
                assemblies.Add(ass);

            var noneSystemAssemblies =
                from a in assemblies
                where  a.Application.IsSystem==false
                select a;

            waitDialog.progressBar1.Maximum = noneSystemAssemblies.Count();
            
            _assemblylist.Clear();
            foreach (BtsAssembly assembly in noneSystemAssemblies)
            {
                try
                {
                    waitDialog.SetLabel(assembly.DisplayName);
                    Assembly a = Assembly.Load(assembly.DisplayName);
                    AssemblyResource assemblyResource = new AssemblyResource(assembly.DisplayName);
                    assemblyResource.Application = assembly.Application.Name;

                    foreach (AssemblyName assemblyName in a.GetReferencedAssemblies())
                        assemblyResource.DependsOn.Add(assemblyName.FullName);

                    ListViewItem lvi = new ListViewItem(assembly.DisplayName);
                    lvi.Tag = assemblyResource;
                    lvi.SubItems.Add("");
                    lvi.SubItems.Add(assembly.Application.Name);
                    lstAssemblies.Items.Add(lvi);
                    _assemblyResources.Add(assemblyResource);
                    _assemblylist.Add(lvi);
                    System.Windows.Forms.Application.DoEvents();
                }
                catch
                {
                    this.Cursor = Cursors.Default;
                }

            }
            waitDialog.Close();
            this.Cursor = Cursors.Default;
        }
        /// <summary>
        /// Gets all BizTalk artifacts (ports and ochestrations) using a assembly
        /// </summary>
        /// <param name="assemblyResource"></param>
        void GetBizTalkArtefactsToUndeploy(BizTalkAssembly assembly)
        {
            //_explorer.Refresh();
            foreach (Microsoft.BizTalk.ExplorerOM.Application application in _explorer.Applications)
            {
                if (application.IsSystem)
                    continue;
                // Receive Ports
                foreach (ReceivePort receivePort in application.ReceivePorts)
                {
                    bool removePort = false;
                    if (receivePort.InboundTransforms != null)
                    {
                        foreach (Transform transform in receivePort.InboundTransforms)
                        {
                            if (transform.BtsAssembly.DisplayName == assembly.Luid &&
                                !BizTalkArtifactItemExist(receivePort.Name))
                            {
                                ListViewItem lvi = new ListViewItem("ReceivePort");
                                lvi.SubItems.Add(receivePort.Name);
                                lvi.SubItems.Add(application.Name);
                                lvBizTalkArtefacts.Items.Add(lvi);
                                removePort = true;
                            }
                        }
                    }
                    if (receivePort.OutboundTransforms != null)
                    {
                        foreach (Transform transform in receivePort.OutboundTransforms)
                        {
                            if (transform.BtsAssembly.DisplayName == assembly.Luid &&
                                !BizTalkArtifactItemExist(receivePort.Name))
                            {
                                ListViewItem lvi = new ListViewItem("ReceivePort");
                                lvi.SubItems.Add(receivePort.Name);
                                lvi.SubItems.Add(application.Name);
                                lvBizTalkArtefacts.Items.Add(lvi);
                                removePort = true;
                            }
                        }
                    }

                    if (removePort)
                        continue;
                    int numberOfLocations = 0;
                    foreach (ReceiveLocation receiveLocation in receivePort.ReceiveLocations)
                    {
                        if (receiveLocation.ReceivePipeline.BtsAssembly.DisplayName == assembly.Luid &&
                            !BizTalkArtifactItemExist(receiveLocation.Name))
                        {
                            ListViewItem lvi = new ListViewItem("ReceiveLocation");
                            lvi.SubItems.Add(receiveLocation.Name);
                            lvi.SubItems.Add(application.Name);
                            lvBizTalkArtefacts.Items.Add(lvi);
                            numberOfLocations++;
                        }
                    }
                    if (numberOfLocations == receivePort.ReceiveLocations.Count && 
                        numberOfLocations > 0 &&
                        !BizTalkArtifactItemExist(receivePort.Name))
                    {
                        ListViewItem lvi = new ListViewItem("ReceivePort");
                        lvi.SubItems.Add(receivePort.Name);
                        lvi.SubItems.Add(application.Name);
                        lvBizTalkArtefacts.Items.Add(lvi);
                    }
                }
                // SendPorts
                foreach (SendPort sendPort in application.SendPorts)
                {
                    bool removePort = false;
                    if (sendPort.OutboundTransforms != null)
                    {
                        foreach (Transform transform in sendPort.OutboundTransforms)
                        {
                            if (transform.BtsAssembly.DisplayName == assembly.Luid &&
                            !BizTalkArtifactItemExist(sendPort.Name))
                            {
                                ListViewItem lvi = new ListViewItem("SendPort");
                                lvi.SubItems.Add(sendPort.Name);
                                lvi.SubItems.Add(application.Name);
                                lvBizTalkArtefacts.Items.Add(lvi);
                                removePort = true;
                            }
                        }
                    }
                    if (sendPort.InboundTransforms != null)
                    {
                        foreach (Transform transform in sendPort.InboundTransforms)
                        {
                            if (transform.BtsAssembly.DisplayName == assembly.Luid &&
                            !BizTalkArtifactItemExist(sendPort.Name))
                            {
                                ListViewItem lvi = new ListViewItem("SendPort");
                                lvi.SubItems.Add(sendPort.Name);
                                lvi.SubItems.Add(application.Name);
                                lvBizTalkArtefacts.Items.Add(lvi);
                                removePort = true;
                            }
                        }
                    }
                    if (removePort)
                        continue;
                    if (sendPort.SendPipeline.BtsAssembly.DisplayName == assembly.Luid &&
                        !BizTalkArtifactItemExist(sendPort.Name))
                    {
                        ListViewItem lvi = new ListViewItem("SendPort");
                        lvi.SubItems.Add(sendPort.Name);
                        lvi.SubItems.Add(application.Name);
                        lvBizTalkArtefacts.Items.Add(lvi);
                    }
                }
                // Orchestrations
                foreach (BtsOrchestration orchestration in application.Orchestrations)
                {
                    if (orchestration.BtsAssembly.DisplayName == assembly.Luid &&
                        !BizTalkArtifactItemExist(orchestration.FullName))
                    {
                        ListViewItem lvi = new ListViewItem("Orchestration");
                        lvi.SubItems.Add(orchestration.FullName);
                        lvi.SubItems.Add(application.Name);
                        lvBizTalkArtefacts.Items.Add(lvi);
                    }
                }
            }   
                
        }
        /// <summary>
        /// Checks if BizTalk artifacts been added to lvBizTalkArtefacts
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        bool BizTalkArtifactItemExist(string name)
        {
            if (lvBizTalkArtefacts.Items.Count == 0)
                return false;
            else
                return lvBizTalkArtefacts.FindItemWithText(name, true, 0) != null;
        }
        /// <summary>
        /// Returns all assemblies, referencing the assembly
        /// </summary>
        /// <param name="assemblyResource"></param>
        /// <returns></returns>
        List<AssemblyResource> GetAllReferencingAssemblies(AssemblyResource assemblyResource)
        {
            List<AssemblyResource> assemblyResources = new List<AssemblyResource>();
            foreach (AssemblyResource ar in _assemblyResources)
            {
                foreach (string luid in ar.DependsOn)
                    if (luid == assemblyResource.Luid)
                    {
                        assemblyResources.Add(ar);
                        break;
                    }
            }
            return assemblyResources;
        }
        /// <summary>
        /// Checks all orchestration ports if they are referencing any assembly
        /// </summary>
        /// <param name="luid"></param>
        void CheckForOrchestrations(string luid)
        {
            // Microsoft.BizTalk.XLANGs.BTXEngine.BTXService
            Assembly assembly = Assembly.Load(luid);

            var orchestrationTypes =
                from t in assembly.GetTypes()
                where t.BaseType.ToString() == "Microsoft.BizTalk.XLANGs.BTXEngine.BTXService"
                select t;

           

            foreach (Type t in orchestrationTypes)
            {
                foreach (Microsoft.BizTalk.ExplorerOM.Application application in _explorer.Applications)
                {
                    foreach (BtsOrchestration orchestration in application.Orchestrations)
                    {
                        if (orchestration.AssemblyQualifiedName.Replace(", ", ",") == t.AssemblyQualifiedName.Replace(", ", ","))
                        {
                            foreach (OrchestrationPort port in orchestration.Ports)
                            {
                                // Check Sendports for assemblies
                                if (port.SendPort != null)
                                {
                                    foreach (Transform transform in port.SendPort.OutboundTransforms)
                                    {
                                        var lvis =
                                            from lvi in _assemblylist
                                            where lvi.Text == transform.BtsAssembly.DisplayName
                                            select lvi;

                                        if (lvis.Count() > 0)
                                        {
                                            lvis.Single().SubItems[1].Text = "Ref";
                                            lvis.Single().Checked = true;
                                        }
                                    }
                                    // Check Sendport pipelines for assemlies

                                    var lvis2 =
                                        from lvi2 in _assemblylist
                                        where lvi2.Text == port.SendPort.SendPipeline.BtsAssembly.DisplayName
                                        select lvi2;

                                    if (lvis2.Count() > 0)
                                    {
                                        lvis2.Single().SubItems[1].Text = "Ref";
                                        lvis2.Single().Checked = true;
                                    }
                                }
                                // Check Receive Ports for assemblies
                                if (port.ReceivePort != null)
                                {
                                    foreach (Transform transform in port.ReceivePort.InboundTransforms)
                                    {
                                        var lvis3 =
                                            from lvi3 in _assemblylist
                                            where lvi3.Text == transform.BtsAssembly.DisplayName
                                            select lvi3;

                                        if (lvis3.Count() > 0)
                                        {
                                            lvis3.Single().SubItems[1].Text = "Ref";
                                            lvis3.Single().Checked = true;
                                        }
                                    }
                                    // Check Receiveports pipelines for assemblies
                                    foreach (ReceiveLocation receiveLocation in port.ReceivePort.ReceiveLocations)
                                    {
                                        var lvis4 =
                                            from lvi4 in _assemblylist
                                            where lvi4.SubItems[0].Text == receiveLocation.ReceivePipeline.BtsAssembly.DisplayName                                            select lvi4;

                                        if (lvis4.Count() > 0)
                                        {
                                            lvis4.Single().SubItems[1].Text = "Ref";
                                            lvis4.Single().Checked = true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

        }
        bool IsUsedInOrchestrations(string luid)
        {
            // Microsoft.BizTalk.XLANGs.BTXEngine.BTXService
            Assembly assembly = Assembly.Load(luid);

            var orchestrationTypes =
                from t in assembly.GetTypes()
                where t.BaseType.ToString() == "Microsoft.BizTalk.XLANGs.BTXEngine.BTXService"
                select t;

            foreach (Type t in orchestrationTypes)
            {
                foreach (Microsoft.BizTalk.ExplorerOM.Application application in _explorer.Applications)
                {
                    foreach (BtsOrchestration orchestration in application.Orchestrations)
                    {
                        if (orchestration.AssemblyQualifiedName.Replace(", ", ",") == t.AssemblyQualifiedName.Replace(", ", ","))
                        {
                            foreach (OrchestrationPort port in orchestration.Ports)
                            {
                                // Check Sendports for assemblies
                                if (port.SendPort != null)
                                {
                                    foreach (Transform transform in port.SendPort.OutboundTransforms)
                                    {
                                        var lvis =
                                            from lvi in _assemblylist
                                            where lvi.Text == transform.BtsAssembly.DisplayName
                                            select lvi;

                                        if (lvis.Count() > 0)
                                            return true;
                                    }
                                    // Check Sendport pipelines for assemlies

                                    var lvis2 =
                                        from lvi2 in _assemblylist
                                        where lvi2.Text == port.SendPort.SendPipeline.BtsAssembly.DisplayName
                                        select lvi2;

                                    if (lvis2.Count() > 0)
                                        return true;
                                }
                                // Check Receive Ports for assemblies
                                if (port.ReceivePort != null)
                                {
                                    foreach (Transform transform in port.ReceivePort.InboundTransforms)
                                    {
                                        var lvis3 =
                                            from lvi3 in _assemblylist
                                            where lvi3.Text == transform.BtsAssembly.DisplayName
                                            select lvi3;

                                        if (lvis3.Count() > 0)
                                            return true;
                                    }
                                    // Check Receiveports pipelines for assemblies
                                    foreach (ReceiveLocation receiveLocation in port.ReceivePort.ReceiveLocations)
                                    {
                                        var lvis4 =
                                            from lvi4 in _assemblylist
                                            where lvi4.SubItems[0].Text == receiveLocation.ReceivePipeline.BtsAssembly.DisplayName
                                            select lvi4;

                                        if (lvis4.Count() > 0)
                                            return true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return false;
        }
        /// <summary>
        /// Adds a status item to lvStatus list
        /// </summary>
        /// <param name="msg"></param>
        void AddStatus(string msg)
        {
            if(progressBarUndeploy.Value<progressBarUndeploy.Maximum)
                progressBarUndeploy.Value++;
    
            lvStatus.SuspendLayout();
            lvStatus.Items.Add(msg);
            System.Windows.Forms.Application.DoEvents();
            lvStatus.ResumeLayout();
        }
        #endregion

        #region Undeploy Methods
        /// <summary>
        /// Top level method to undeploy all artifacts and assemblies
        /// </summary>
        void Undeploy()
        {
            try
            {
                progressBarUndeploy.Visible = true;
                progressBarUndeploy.Maximum = lvUndeploy.Items.Count + 7;

                AddStatus("Undeploy started..."); 
                _explorer.Refresh();
                List<BizTalkArtifact> bizTalkArtifact = new List<BizTalkArtifact>();
                foreach (ListViewItem lvi in lvBizTalkArtefacts.Items)
                    bizTalkArtifact.Add(new BizTalkArtifact()
                    {
                        Type = lvi.SubItems[0].Text,
                        Name = lvi.SubItems[1].Text,
                        ApplicationName = lvi.SubItems[2].Text
                    });
                if (lvBizTalkArtefacts.Items.Count > 0)
                {
                    AddStatus("Disabling receive ports...");
                    DisableReceivePortsPorts(bizTalkArtifact);
                    AddStatus("Stopping send ports...");
                    StopSendPortsPorts(bizTalkArtifact);
                    AddStatus("Unenlisting orchestrations...");
                    UnEnlistOrchestrations(bizTalkArtifact);
                    AddStatus("Removing receive ports...");
                    RemoveReceivePorts(bizTalkArtifact);
                    AddStatus("Removing send ports...");
                    RemoveSendPorts(bizTalkArtifact);
                }
                else
                {
                    AddStatus("No ports to remove");
                    progressBarUndeploy.Maximum = lvUndeploy.Items.Count + 2;
                }


                AddStatus("Starting to remove assemblies...");
                RemoveAssemblies();
                AddStatus("Undeploy were successfull");
            }
            catch (Exception ex)
            {
                AddStatus(ex.Message);
                MessageBox.Show("Unable to preform undeploy\n" + ex.Message);
            }
        }
        void DisableReceivePortsPorts(List<BizTalkArtifact> bizTalkArtifacts)
        {
            var ReceivePorts =
                from a in bizTalkArtifacts
                where a.Type == "ReceivePort"
                select a;

            foreach (BizTalkArtifact artifact in ReceivePorts)
            {
                ReceivePort receiveport = _explorer.Applications[artifact.ApplicationName].ReceivePorts[artifact.Name];

                foreach (ReceiveLocation receiveLocation in receiveport.ReceiveLocations)
                    receiveLocation.Enable = false;
            }
            _explorer.SaveChanges();
        }
        void StopSendPortsPorts(List<BizTalkArtifact> bizTalkArtifacts)
        {
            var SendPorts =
               from a in bizTalkArtifacts
               where a.Type == "SendPort"
               select a;

            foreach (BizTalkArtifact artifact in SendPorts)
            {
                SendPort receiveport = _explorer.Applications[artifact.ApplicationName].SendPorts[artifact.Name];
                receiveport.Status = PortStatus.Bound;
            }
            _explorer.SaveChanges();
        }
        void UnEnlistOrchestrations(List<BizTalkArtifact> bizTalkArtifacts)
        {
            var Orchestrations =
              from a in bizTalkArtifacts
              where a.Type == "Orchestration"
              select a;

            foreach (BizTalkArtifact artifact in Orchestrations)
            {
                BtsOrchestration orchestration = _explorer.Applications[artifact.ApplicationName].Orchestrations[artifact.Name];
                orchestration.Status = OrchestrationStatus.Unenlisted;

                foreach (OrchestrationPort port in orchestration.Ports)
                {
                    port.ReceivePort = null;
                    port.SendPort = null;
                    port.SendPortGroup = null;
                }
                _explorer.SaveChanges();
            }
        }
        void RemoveReceivePorts(List<BizTalkArtifact> bizTalkArtifacts)
        {
            var ReceivePorts =
               from a in bizTalkArtifacts
               where a.Type == "ReceivePort"
               select a;

            foreach (BizTalkArtifact artifact in ReceivePorts)
            {
                ReceivePort receiveport = _explorer.Applications[artifact.ApplicationName].ReceivePorts[artifact.Name];
                if (cbLeavePorts.Checked)
                {
                    receiveport.InboundTransforms.Clear();
                    foreach (ReceiveLocation receiveLocation in receiveport.ReceiveLocations)
                        receiveLocation.ReceivePipeline = _explorer.Pipelines["Microsoft.BizTalk.DefaultPipelines.PassThruReceive"];
                }
                else
                    _explorer.RemoveReceivePort(receiveport);
                
            }
            _explorer.SaveChanges();
        }
        void RemoveSendPorts(List<BizTalkArtifact> bizTalkArtifacts)
        {
            var SendPorts =
               from a in bizTalkArtifacts
               where a.Type == "SendPort"
               select a;

            foreach (BizTalkArtifact artifact in SendPorts)
            {
                SendPort sendPort = _explorer.Applications[artifact.ApplicationName].SendPorts[artifact.Name];
                if (cbLeavePorts.Checked)
                {
                    sendPort.OutboundTransforms.Clear();
                    sendPort.SendPipeline = _explorer.Pipelines["Microsoft.BizTalk.DefaultPipelines.PassThruTransmit"];
                }
                else
                    _explorer.RemoveSendPort(sendPort);
            }
            _explorer.SaveChanges();
        }
        void RemoveAssemblies()
        {
            List<BizTalkArtifact> bizTalkAssembies = new List<BizTalkArtifact>();

            foreach (ListViewItem lvi in lvUndeploy.Items)
                bizTalkAssembies.Add(new BizTalkArtifact()
                {
                    Order = int.Parse(lvi.SubItems[0].Text),
                    Name = lvi.SubItems[1].Text,
                    ApplicationName = lvi.Tag.ToString()
                });

            var assemblies =
                from a in bizTalkAssembies
                orderby a.Order 
                select a;

            foreach (BizTalkArtifact artifact in assemblies)
            {
                AddStatus("Removing " + artifact.Name + " ...");
                RemoveAssembly(artifact);
            }
            if (cbUninstallFromGAC.Checked)
            { 
                string gacUtilPath = Path.Combine(ConfigurationManager.AppSettings["GacUtilPath"], "GacUtil.exe");
                if(!File.Exists(gacUtilPath))
                    MessageBox.Show("Can not find the path to GacUtil.exe. Please update the Blogical.Tools.BizTalkUndeployHelper.exe.config file with the correct path");
                else
                {
                    foreach (BizTalkArtifact artifact in assemblies)
                    {
                        AddStatus("Removing from GAC " + artifact.Name );
                        RemoveAssemblyFromGAC(artifact);
                    }
                }
            }
        }
        void RemoveAssembly(BizTalkArtifact bizTalkArtifact)
        {
            try
            {
                using (ProcessHelper p = new ProcessHelper())
                {
                    try
                    {
                        string formatString = @"RemoveResource -ApplicationName:""{0}"" -Luid:""{1}"" -Server={2} -Database={3}";
                        string cmd = string.Format(formatString,
                            bizTalkArtifact.ApplicationName,
                            bizTalkArtifact.Name,
                            this.txtServer.Text,
                            this.txtDatabase.Text);

                        p.Execute("BTSTask.exe", cmd, 30000);
                    }
                    catch(Exception ex)
                    {
                        throw;
                    }
                    Thread.Sleep(1000);
                    if (!String.IsNullOrEmpty( ProcessHelper.ErrorMessage ))
                        throw new Exception(ProcessHelper.ErrorMessage);
                }
            }
            catch
            {
                throw;
            }
        }
        void RemoveAssemblyFromGAC(BizTalkArtifact bizTalkArtifact)
        {
            string gacUtilPath = Path.Combine(ConfigurationManager.AppSettings["GacUtilPath"], "GacUtil.exe");

            try
            {
                using (ProcessHelper p = new ProcessHelper())
                {
                    try
                    {
                        string formatString = @"/u ""{0}""";
                        string cmd = string.Format(formatString, bizTalkArtifact.Name);

                        p.Execute(gacUtilPath, cmd, 30000);
                    }
                    catch (Exception ex)
                    {
                        throw;
                    }
                    Thread.Sleep(1000);
                    if (!String.IsNullOrEmpty(ProcessHelper.ErrorMessage))
                        throw new Exception(ProcessHelper.ErrorMessage);
                }
            }
            catch
            {
                throw;
            }
        }
        #endregion

    }
}